﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using TaoDingPvServer.Common;

namespace TaoDingPvServer.Network
{
    public class WebsocketServer
    {
        //原始事件
        public event Action<string> OnConnect;
        public event Action<string> OnDisConnect;
        public event Action<string,string> OnReceive;

        private TcpServer m_TcpServer;
        private WebsocketProtocol m_Protocol = new WebsocketProtocol();
        
        public List<TcpSession> GetSessions()
        {
            return m_TcpServer.GetSessions();
        }

        public bool Start(int Port, int backlog = 200)
        {
            m_TcpServer = new TcpServer();
            m_TcpServer.OnConnect += new Action<TcpSession>((Session) =>
            {
                OnConnect?.Invoke(Session.SessionId);
            });
            m_TcpServer.OnDisConnect += new Action<TcpSession>((Session) =>
            {
                OnDisConnect?.Invoke(Session.SessionId);
            });

            m_TcpServer.OnReceive += new Action<TcpSession>((Session) =>
            {
                OnReceiveDo(Session);
            });

            bool b = m_TcpServer.Start(Port, backlog);
            return b;

        }
        public void Stop()
        {
            if (m_TcpServer != null)
            {
                m_TcpServer.Stop();
                m_TcpServer = null;
            }
        }

        public void Send(string Data)
        {
            List<TcpSession> Sessions = m_TcpServer.GetSessions();
            lock ((Sessions as ICollection).SyncRoot)
            {
                foreach (TcpSession Session in Sessions)
                {
                    byte[] Frame = m_Protocol.BuildFrame(0x01, Encoding.UTF8.GetBytes(Data));
                    Session.Send(Frame);
                }
            }
        }
        protected void OnReceiveDo(TcpSession Session)
        {
            while (true)
            {
                //未握手情况下
                if (!Session.TagBool)
                {
                    Session.TagInt++;
                    Dictionary<string, string> dic;
                    bool a = m_Protocol.GetHandshakeFrame(Session.DataBuffer, out dic);
                    if (a)
                    {
                        //发送握手应答
                        string strRespone = "HTTP/1.1 101 Switching Protocols\r\n" +
                                            "Upgrade: websocket\r\n" +
                                            "Connection: Upgrade\r\n";
                        string key = dic["sec-websocket-key"] + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
                        SHA1 hasher = SHA1.Create();
                        key = Convert.ToBase64String(hasher.ComputeHash(Encoding.UTF8.GetBytes(key))).ToString();
                        strRespone = strRespone + "Sec-WebSocket-Accept: " + key + "\r\n\r\n";

                        Session.Send(Encoding.UTF8.GetBytes(strRespone));
                        OnConnect?.Invoke(Session.SessionId);

                        Session.TagBool = true;
                        break;
                    }
                    else
                    {
                        //如果已经接收到2帧还未解析出握手帧，判定为非法连接,关闭次连接
                        if (Session.TagInt > 1)
                        {
                            List<TcpSession> Sessions = GetSessions();
                            lock ((Sessions as ICollection).SyncRoot)
                            {
                                Sessions.Remove(Session);
                            }
                            Session.Close();
                        }
                        return;
                    }
                }
                Session.TagInt = 0;

                RFC6455Frame RFrame;
                bool bContinue = m_Protocol.GetFrame(Session.DataBuffer, out RFrame);
                //未解析到帧
                if (RFrame == null)
                {
                    //可以继续获取帧
                    if (bContinue)
                    {
                        continue;
                    }
                    //需要接收数据
                    else
                    {
                        return;
                    }
                }
                //02-解析数据
                if (RFrame.OpCode == 0x01)
                {
                    if (RFrame.Data != null)
                    {
                        string JsonStr = Encoding.UTF8.GetString(RFrame.Data);
                        OnReceive?.Invoke(Session.SessionId, JsonStr);
                    }
                }
                //09-ping
                else if (RFrame.OpCode == 0x09)
                {
                    //发送pong
                    byte[] SFrame = m_Protocol.BuildFrame(0x0A, new byte[0]);
                    Session.Send(SFrame);
                }
                //08-关闭连接
                else if (RFrame.OpCode == 0x08)
                {
                    Session.Close();
                }
            }
        }
    }
}
